<template>
  <div>
    <div style="display:flex; align-items:center; justify-content:space-between; gap:8px; margin-bottom:12px">
      <div style="display:flex; align-items:center; gap:8px">
        <el-input v-model="searchQuery" placeholder="按名称/编码搜索" clearable @clear="clearSearch" style="width:360px" />
      </div>
      <div>
        <!-- hide add button when no permission -->
        <el-button v-if="canAdd" type="primary" @click="openAdd">新增菜单</el-button>
      </div>
    </div>

    <el-table
      :data="menusView"
      row-key="id"
      border
      stripe
      style="width:100%"
      :tree-props="{ children: 'children' }"
    >
      <el-table-column label="序号" width="80">
        <template #default="{ $index }">{{ $index + 1 }}</template>
      </el-table-column>

      <el-table-column prop="name" label="名称" />
      <el-table-column prop="code" label="编码" />
      <el-table-column prop="url" label="链接" />
      <el-table-column prop="order_num" label="排序" width="120" />
      <el-table-column prop="icon" label="图标" width="120" />
      <el-table-column prop="is_function" label="功能" width="90">
        <template #default="{ row }">{{ row.is_function ? '是' : '否' }}</template>
      </el-table-column>

      <el-table-column label="操作" width="130">
        <template #default="{ row }">
          <!-- hide edit/delete when no permission -->
          <el-button v-if="canEdit" size="small" @click="openEdit(row)">编辑</el-button>
          <el-button v-if="canDelete" size="small" type="danger" @click="remove(row)" style="margin-left:8px">删除</el-button>
        </template>
      </el-table-column>
    </el-table>

    <el-alert v-if="error" type="error" :title="error" show-icon style="margin-top:12px" />

    <el-dialog :title="editing.id ? '编辑菜单' : '新增菜单'" v-model="showModal" width="640px">
      <el-form ref="formRef" :model="editing" label-width="100px">
        <el-form-item label="名称" prop="name">
          <el-input v-model="editing.name" />
        </el-form-item>

        <el-form-item label="父菜单">
          <el-select v-model="editing.parent_id" filterable placeholder="选择父菜单" style="width:100%">
            <el-option :label="'(无/根)'" :value="null" />
            <el-option v-for="opt in parentOptions" :key="opt.id" :label="opt.label" :value="opt.id" />
          </el-select>
        </el-form-item>

        <el-form-item label="编码">
          <el-input v-model="editing.code" />
        </el-form-item>

        <el-form-item label="链接">
          <el-input v-model="editing.url" />
        </el-form-item>

        <el-form-item label="排序">
          <el-input v-model="editing.order_num" />
        </el-form-item>

        <el-form-item label="图标">
          <el-input v-model="editing.icon" />
        </el-form-item>

        <el-form-item label="是否功能">
          <el-switch v-model="editing.is_function" :active-value="1" :inactive-value="0" />
        </el-form-item>

        <el-form-item label="是否全屏">
          <el-switch v-model="editing.full_page" active-value="1" inactive-value="0" />
        </el-form-item>

        <el-form-item label="iframe 链接">
          <el-input v-model="editing.iframe_url" />
        </el-form-item>

        <el-form-item label="备注">
          <el-input type="textarea" v-model="editing.remarks" :rows="3" />
        </el-form-item>
      </el-form>

      <template #footer>
        <el-button @click="closeModal">取消</el-button>
        <!-- only show save when user has add/edit permission for current mode -->
        <el-button v-if="(editing.id && canEdit) || (!editing.id && canAdd)" type="primary" @click="submit">保存</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, computed, onMounted, watch } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useAuthStore } from '../stores/auth'

const auth = useAuthStore()
// permission flags for this page
const canAdd = computed(() => auth.hasPermission('0103', '新增'))
const canEdit = computed(() => auth.hasPermission('0103', '编辑'))
const canDelete = computed(() => auth.hasPermission('0103', '删除'))
const menus = ref<any[]>([])
const error = ref('')

const searchQuery = ref('')
let searchTimer: number | null = null

const showModal = ref(false)
const editing = reactive<any>({ id: null, name: '', parent_id: null, order_num: '', url: '', icon: '', remarks: '', code: '', full_page: 0, iframe_url: '', is_function: 0 })
const formRef = ref<any>(null)

const parentOptions = computed(() => flattenMenus(menus.value))

const menusView = computed(() => {
  const q = String(searchQuery.value || '').trim().toLowerCase()
  if (!q) return menus.value
  // filter tree by name or code, keep ancestors for context
  function filterNodes(nodes: any[]) {
    const res: any[] = []
    for (const n of nodes) {
      const match = (String(n.name || '').toLowerCase().includes(q) || String(n.code || '').toLowerCase().includes(q))
      const children = n.children && n.children.length ? filterNodes(n.children) : []
      if (match || children.length) {
        res.push({ ...n, children })
      }
    }
    return res
  }
  return filterNodes(menus.value)
})

async function load() {
  error.value = ''
  try {
    // For admin menu list we must fetch ALL menus (not role-filtered navigation menus).
    // Call the direct endpoint /api/menus which returns the full tree.
    const res = await auth.apiFetch('/menus')
    menus.value = res.menus || []
  } catch (e: any) {
    error.value = '加载菜单失败'
  }
}

function flattenMenus(nodes: any[], prefix = ''): any[] {
  const out: any[] = []
  nodes.forEach(n => {
    out.push({ id: n.id, label: `${prefix}${n.name}` })
    if (n.children && n.children.length) {
      out.push(...flattenMenus(n.children, prefix + '  '))
    }
  })
  return out
}

onMounted(() => { load() })

function openAdd() {
  if (!canAdd.value) { ElMessage.warning('没有新增权限'); return }
  editing.id = null
  editing.name = ''
  editing.parent_id = null
  editing.order_num = ''
  editing.url = ''
  editing.icon = ''
  editing.remarks = ''
  editing.code = ''
  editing.full_page = 0
  editing.iframe_url = ''
  editing.is_function = 0
  showModal.value = true
}

function openEdit(row: any) {
  if (!canEdit.value) { ElMessage.warning('没有编辑权限'); return }
  editing.id = row.id
  editing.name = row.name
  editing.parent_id = row.parent_id ?? null
  editing.order_num = row.order_num || ''
  editing.url = row.url || ''
  editing.icon = row.icon || ''
  editing.remarks = row.remarks || ''
  editing.code = row.code || ''
  editing.full_page = row.full_page ? 1 : 0
  editing.iframe_url = row.iframe_url || ''
  editing.is_function = row.is_function ? 1 : 0
  showModal.value = true
}

function closeModal() { showModal.value = false }

async function submit() {
  error.value = ''
  try {
    if (!editing.name) {
      ElMessage.error('请填写菜单名称')
      return
    }

    // permission guard before submitting
    if (editing.id && !canEdit.value) { ElMessage.error('没有编辑权限'); return }
    if (!editing.id && !canAdd.value) { ElMessage.error('没有新增权限'); return }

    const payload = {
      name: editing.name,
      parent_id: editing.parent_id,
      order_num: editing.order_num,
      url: editing.url,
      icon: editing.icon,
      remarks: editing.remarks,
      code: editing.code,
      full_page: editing.full_page,
      iframe_url: editing.iframe_url,
      is_function: editing.is_function
    }

    if (editing.id) {
      await auth.apiFetch(`/menus/${editing.id}`, { method: 'PUT', body: JSON.stringify(payload) })
      ElMessage.success('编辑成功')
    } else {
      await auth.apiFetch('/menus', { method: 'POST', body: JSON.stringify(payload) })
      ElMessage.success('新增成功')
    }
    closeModal()
    await load()
  } catch (e: any) {
    try { const body = await e.json(); error.value = body.message || '操作失败' } catch { error.value = '操作失败' }
    ElMessage.error(error.value)
  }
}

async function remove(row: any) {
  error.value = ''
  if (!canDelete.value) { ElMessage.warning('没有删除权限'); return }
  ElMessageBox.confirm(`确定删除菜单 ${row.name} ?`, '删除确认', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' })
    .then(async () => {
      try {
        // try normal DELETE first
        await auth.apiFetch(`/menus/${row.id}`, { method: 'DELETE' })
        ElMessage.success('删除成功')
        await load()
      } catch (e: any) {
        // robust error handling: try to read server response and detect "Cannot DELETE"
        let bodyText = ''
        try {
          if (e && typeof e.json === 'function') {
            const parsed = await e.json().catch(() => null)
            if (parsed && parsed.message) bodyText = parsed.message
            else if (parsed) bodyText = JSON.stringify(parsed)
          } else if (e && typeof e.text === 'function') {
            bodyText = await e.text().catch(() => '')
          } else if (e && e.message) {
            bodyText = e.message
          }
        } catch (_) { /* ignore parsing errors */ }

        // If backend rejects DELETE (e.g. returns "Cannot DELETE /api/menus/72" or 404/405), try method-override fallback
        if (String(bodyText).includes('Cannot DELETE') || (e && e.status && [404, 405].includes(e.status))) {
          try {
            await auth.apiFetch(`/menus/${row.id}`, {
              method: 'POST',
              headers: { 'Content-Type': 'application/json', 'X-HTTP-Method-Override': 'DELETE' },
              body: JSON.stringify({ _method: 'DELETE' })
            })
            ElMessage.success('删除成功')
            await load()
            return
          } catch (e2: any) {
            try { const b2 = await e2.json(); error.value = b2.message || '删除失败' } catch { error.value = '删除失败' }
            ElMessage.error(error.value)
            return
          }
        }

        try { const body = await e.json(); error.value = body.message || '删除失败' } catch { error.value = bodyText || '删除失败' }
        ElMessage.error(error.value)
      }
    }).catch(() => {})
}

function clearSearch() {
  searchQuery.value = ''
  load()
}

watch(searchQuery, () => {
  if (searchTimer) clearTimeout(searchTimer)
  searchTimer = window.setTimeout(() => { load() }, 300)
})
</script>

<style scoped>
/* keep styles minimal and consistent */
</style>
